/********************************************
 * 功能说明: 
 * 模块名称: 
 * 系统名称: 
 * 软件版权: 
 * 系统版本: 1.0.0
 * 开发人员: zhangfb
 * 开发时间: 2019/3/24 19:37
 * 审核人员: 
 * 相关文档: 
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.hyacinth.thread;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;

/**
 * 具有监控功能的线程池
 * @author zhangfb
 * @version 1.0.0.1
 * @since JDK 1.8
 */
public class HyThreadPool {

    private static final Logger LOGGER = LoggerFactory.getLogger(HyThreadPool.class);

    /**
     * 任务执行器
     */
    abstract static class Task implements Runnable{

        String taskName;

        Task(String taskName) {
            this.taskName = taskName;
        }

        protected abstract void execute() throws Exception;

        @Override
        public void run() {
            LOGGER.debug("excuteTime={},ThreadID={},taskName={}|正在执行",System.currentTimeMillis(), Thread.currentThread().getId(), taskName);
            try {
                execute();
            } catch (Exception e) {
                LOGGER.error("excuteTime={},ThreadID={},taskName={}|执行出错",System.currentTimeMillis(), Thread.currentThread().getId(), taskName, e);
            }
        }

    }

    /**
     * 自定义实现固定大小线程池
     * 自定义：
     * <p>
     *     1、线程工厂
     *     2、拒绝策略
     *     3、执行进度
     * </p>
     * @return
     */
    public static ExecutorService newFixedWithRejectThreadPool() {
        return new TraceThreadPoolExecutor(10, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(20),
                // 自定义线程工厂，将每个线程设置为守护线程
//                new ThreadFactory() {
//                    @Override
//                    public Thread newThread(Runnable task) {
//                        Thread t = new Thread(task);
//                        t.setDaemon(true);
//                        LOGGER.debug("create " + t.getName());
//                        return t;
//                    }
//                }
                Executors.defaultThreadFactory()
                // 拒绝策略,打印被拒绝的线程栈
                , new RejectedExecutionHandler() {
                    @Override
                    public void rejectedExecution(Runnable task, ThreadPoolExecutor executor) {
                        LOGGER.debug(((Task) task).taskName + " is discard");
                    }
        }) {
            protected void beforeExecute(Thread t, Runnable task) {
                LOGGER.debug("任务={},执行线程ID={}|准备执行", ((Task) task).taskName, t.getId());
            }

            protected void afterExecute(Thread t, Runnable task) {
                LOGGER.debug("任务={},执行线程ID={}|执行完成", ((Task) task).taskName, t.getId());
            }

            protected void terminated() {
                System.out.println("线程池退出!");
            }
        };
    }

    /**
     * 打印异常线程栈的线程池
     */
    public static class TraceThreadPoolExecutor extends ThreadPoolExecutor {

        TraceThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        }

        public void execute(Runnable task) {
            super.execute(wrap(task, clientTrace(), Thread.currentThread().getName()));
        }

        private Runnable wrap(final Runnable task, final Exception clientTrace, String name) {
            return new Task(((Task)task).taskName) {
                @Override
                protected void execute() throws Exception {
                    try {
                        task.run();
                    } catch (Exception e) {
                        clientTrace.printStackTrace();
                        throw e;
                    }
                }
            };
        }

        private Exception clientTrace() {
            return new Exception("Client stack trace");
        }
    }
}
